"""
验证服务单元测试
==============
"""

import pytest

from redfire_framework.core.security import (
    EmailValidator,
    PasswordValidator,
    PhoneNumberValidator,
    UsernameValidator,
    ValidationService,
    validate_email,
    validate_password,
    validate_phone,
    validate_username,
)


class TestEmailValidator:
    """邮箱验证器测试"""

    def test_valid_emails(self):
        """测试有效邮箱"""
        validator = EmailValidator()
        valid_emails = [
            "test@example.com",
            "user.name@domain.org",
            "user+tag@example.co.uk",
            "123@domain.com",
        ]

        for email in valid_emails:
            assert validator.validate(email), f"邮箱 {email} 应该有效"

    def test_invalid_emails(self):
        """测试无效邮箱"""
        validator = EmailValidator()
        invalid_emails = [
            "invalid",
            "@domain.com",
            "user@",
            "user@domain",
            "user..name@domain.com",
            "user@domain..com",
            "",
            None,
        ]

        for email in invalid_emails:
            assert not validator.validate(email), f"邮箱 {email} 应该无效"


class TestPasswordValidator:
    """密码验证器测试"""

    def test_valid_passwords(self):
        """测试有效密码"""
        validator = PasswordValidator(min_length=8, require_special=True)
        valid_passwords = ["Password123!", "Test@123", "MySecret$456"]

        for password in valid_passwords:
            assert validator.validate(password), f"密码 {password} 应该有效"

    def test_invalid_passwords(self):
        """测试无效密码"""
        validator = PasswordValidator(min_length=8, require_special=True)
        invalid_passwords = [
            "short",  # 太短
            "nouppercase123!",  # 无大写字母
            "NOLOWERCASE123!",  # 无小写字母
            "NoDigits!",  # 无数字
            "NoSpecial123",  # 无特殊字符
            "",  # 空字符串
            None,  # None值
        ]

        for password in invalid_passwords:
            assert not validator.validate(password), f"密码 {password} 应该无效"

    def test_password_without_special_requirement(self):
        """测试不要求特殊字符的密码"""
        validator = PasswordValidator(min_length=8, require_special=False)

        # 这个密码没有特殊字符，但应该有效
        assert validator.validate("Password123")


class TestPhoneNumberValidator:
    """手机号验证器测试"""

    def test_valid_phone_numbers(self):
        """测试有效手机号"""
        validator = PhoneNumberValidator()
        valid_phones = ["13800138000", "15912345678", "18888888888"]

        for phone in valid_phones:
            assert validator.validate(phone), f"手机号 {phone} 应该有效"

    def test_invalid_phone_numbers(self):
        """测试无效手机号"""
        validator = PhoneNumberValidator()
        invalid_phones = [
            "12800138000",  # 第二位不是3-9
            "1380013800",  # 位数不足
            "138001380000",  # 位数过多
            "abcdefghijk",  # 非数字
            "",  # 空字符串
            None,  # None值
        ]

        for phone in invalid_phones:
            assert not validator.validate(phone), f"手机号 {phone} 应该无效"


class TestUsernameValidator:
    """用户名验证器测试"""

    def test_valid_usernames(self):
        """测试有效用户名"""
        validator = UsernameValidator(min_length=3, max_length=20)
        valid_usernames = ["user123", "test_user", "User_Name_123", "abc"]

        for username in valid_usernames:
            assert validator.validate(username), f"用户名 {username} 应该有效"

    def test_invalid_usernames(self):
        """测试无效用户名"""
        validator = UsernameValidator(min_length=3, max_length=20)
        invalid_usernames = [
            "ab",  # 太短
            "a" * 21,  # 太长
            "user-name",  # 包含连字符
            "user name",  # 包含空格
            "user@name",  # 包含特殊字符
            "",  # 空字符串
            None,  # None值
        ]

        for username in invalid_usernames:
            assert not validator.validate(username), f"用户名 {username} 应该无效"


class TestValidationFunctions:
    """验证函数测试"""

    def test_validate_email_function(self):
        """测试邮箱验证函数"""
        assert validate_email("test@example.com")
        assert not validate_email("invalid_email")

    def test_validate_password_function(self):
        """测试密码验证函数"""
        assert validate_password("Password123!")
        assert not validate_password("weak")

    def test_validate_phone_function(self):
        """测试手机号验证函数"""
        assert validate_phone("13800138000")
        assert not validate_phone("invalid_phone")

    def test_validate_username_function(self):
        """测试用户名验证函数"""
        assert validate_username("valid_user")
        assert not validate_username("u")


class TestValidationService:
    """验证服务测试"""

    @pytest.fixture
    def validation_service(self):
        """验证服务fixture"""
        return ValidationService()

    def test_validate_user_data_valid(self, validation_service):
        """测试验证有效用户数据"""
        valid_data = {
            "username": "testuser",
            "email": "test@example.com",
            "password": "Password123!",
            "phone": "13800138000",
        }

        # 应该不抛出异常
        validation_service.validate_user_data(valid_data)

    def test_validate_user_data_missing_required(self, validation_service):
        """测试缺少必填字段"""
        invalid_data = {
            "username": "testuser"
            # 缺少email和password
        }

        with pytest.raises(Exception):  # 应该抛出验证异常
            validation_service.validate_user_data(invalid_data)

    def test_validate_user_data_invalid_fields(self, validation_service):
        """测试无效字段值"""
        invalid_data = {
            "username": "a",  # 太短
            "email": "invalid_email",
            "password": "weak",
            "phone": "invalid_phone",
        }

        with pytest.raises(Exception):  # 应该抛出验证异常
            validation_service.validate_user_data(invalid_data)


# 性能测试
class TestValidationPerformance:
    """验证性能测试"""

    @pytest.mark.slow
    def test_email_validation_performance(self):
        """测试邮箱验证性能"""
        validator = EmailValidator()
        email = "test@example.com"

        # 测试大量验证的性能
        import time

        start_time = time.time()

        for _ in range(10000):
            validator.validate(email)

        end_time = time.time()
        duration = end_time - start_time

        # 10000次验证应该在1秒内完成
        assert duration < 1.0, f"邮箱验证性能测试失败，耗时: {duration}秒"


# 边界测试
class TestValidationBoundary:
    """验证边界测试"""

    def test_password_length_boundary(self):
        """测试密码长度边界"""
        validator = PasswordValidator(min_length=8, require_special=False)

        # 边界值测试
        assert not validator.validate("1234567")  # 7位，应该无效
        assert validator.validate("12345678aA")  # 8位，包含大小写字母、数字，应该有效

    def test_username_length_boundary(self):
        """测试用户名长度边界"""
        validator = UsernameValidator(min_length=3, max_length=20)

        # 边界值测试
        assert not validator.validate("ab")  # 2位，应该无效
        assert validator.validate("abc")  # 3位，应该有效
        assert validator.validate("a" * 20)  # 20位，应该有效
        assert not validator.validate("a" * 21)  # 21位，应该无效
